import commonMixin from '../mixins/common.js'

// 每种类型的日期权重
const DATE_TYPES = {
  year: 1,
  month: 2,
  day: 3,
  hour: 4,
  min: 5
}

export default {
  name: 'cm-picker-solar',
  mixins: [
    commonMixin
  ],
  props: {
    // 日期选择器的种类，year年 / month月 / day日 / hour小时 / min分钟
    type: {
      default: 'min',
      type: String,
      validator (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['year', 'month', 'day', 'hour', 'min'].indexOf(value) !== -1
      }
    },
    // 起始日期,格式YYYY/MM/DD HH:SS，不支持100年以前，以及公元前时间
    start: {
      default: '1900/01/01 00:00',
      type: String
    },
    // 结束日期,格式YYYY/MM/DD HH:SS，不支持100年以前，以及公元前时间
    end: {
      default: '2100/12/31 23:59',
      type: String
    },
    // 初始化选中的日期
    values: {
      default: 'now',
      type: String
    },
    // 选中框样式，只能传样式CSS字符串
    indicatorStyle: {
      type: String,
      default: 'background-color: rgba(0, 0, 0, 0.04);'
    }
  },
  data () {
    return {
      // 真正决定视图内容的列表数据
      dataList: [],
      // 真正决定视图内容的选中索引集
      indexes: [],
      // 列表列数
      colNum: DATE_TYPES[this.type]
      /*
        没在data中定义，但是是重要的组件参数的
        startDate 起始日期
        endDate 结束日期
      */
    }
  },
  computed: {
  },
  methods: {
    // 改变选中项触发
    changeHandler (e) {
      if (!e.isSet) {
        // 原生change事件，要设置100ms间隔的锁，避免连续触发，影响性能
        // 因为uni-app的bug，picker-view放置在popup中会有初始化错乱的bug，导致连续错误地触发此事件
        if (this.changeLock) {
          return
        }
        this.changeLock = true
        clearTimeout(this.changeTimer)
        this.changeTimer = setTimeout(() => {
          this.changeLock = false
        }, 100)
      }
      
      let val = e.detail.value
      // 先更新数据集
      this.updateData(val)
      // 获取text集
      const valueText = val.map((des, index) => {
        if (!Array.isArray(this.dataList[index]) || this.dataList[index].length === 0) {
          return null
        }
        if (des < this.dataList[index].length) {
          return this.dataList[index][des].text
        }
        // 处理长度超标的情况，修正val值
        const fixed = this.dataList[index].length - 1
        val[index] = fixed
        return this.dataList[index][fixed].text
      })
      // 获取value集
      const valueList = val.map((des, index) => {
        if (!Array.isArray(this.dataList[index]) || this.dataList[index].length === 0) {
          return null
        }
        // 由于之前获取text集时已经修正过val值，所以这里不会再出现长度超标的情况
        return this.dataList[index][des].value
      })
      // 更新index数据
      this.indexes = val
      // 触发事件
      this.$emit('change', valueList, valueText, val)
    },

    // 设定数据集和选中值，可以用于手动初始化，注意此处values必须为Date对象
    set (startDate, endDate, values) {
      // 初始化数据集
      this.setData(startDate, endDate)
      // 初始化选中值
      this.setValues(values)
    },
    
    setData (startDate, endDate) {
      // 初始化数据集和索引集
      this.dataList = []
      this.indexes = []
      // 更新起止时间
      this.startDate = this.getDate(startDate)
      this.endDate = this.getDate(endDate)
      if (!this.startDate || !this.endDate) {
        // 各种非法日期
        return
      }
      
      // 更新动态更新年的数据
      if (this.colNum >= DATE_TYPES.year) {
        const yearList = this.initNumCol(this.startDate.year, this.endDate.year)
        this.dataList.push(yearList)
        this.indexes.push(0)
      }
      // 动态更新月的数据
      if (this.colNum >= DATE_TYPES.month) {
        this.indexes.push(0)
        const monthList = this.initNumCol(this.startDate.month, 12)
        this.dataList.push(monthList)
        
        // 动态更新日的数据
        if (this.colNum >= DATE_TYPES.day) {
          this.indexes.push(0)
          const dayNum = this.getMonthDay(this.startDate.year, this.startDate.month)
          const dayStart = this.startDate.day
          const dayList = this.initNumCol(dayStart, dayNum)
          this.dataList.push(dayList)
        }        
      }
      // 初始化时数据
      if (this.colNum >= DATE_TYPES.hour) {
        const hourList = this.initNumCol(0, 23)
        this.dataList.push(hourList)
        this.indexes.push(0)
      }
      // 初始化分数据
      if (this.colNum >= DATE_TYPES.min) {
        const minList = this.initNumCol(0, 59)
        this.dataList.push(minList)
        this.indexes.push(0)
      }
    },
    
    updateData (values) {
      if (typeof values[0] === 'number' && this.colNum >= DATE_TYPES.month) {
        // 年改变了，更新月的级联数据
        let yearIndex = values[0]
        if (yearIndex < 0) { yearIndex = 0 }
        if (yearIndex >= this.dataList[0].length) { yearIndex = this.dataList[0].length - 1 }
        const startMonth = yearIndex === 0 ? this.startDate.month : 1
        const endMonth = yearIndex === this.dataList[0].length - 1 ? this.endDate.month : 12
        const monthList = this.initNumCol(startMonth, endMonth)
        this.$set(this.dataList, 1, monthList)
        
        if (typeof values[1] === 'number' && this.colNum >= DATE_TYPES.day) {
          // 月改变了，更新日的级联数据
          let monthIndex = values[1]
          if (monthIndex < 0) { monthIndex = 0 }
          if (monthIndex >= this.dataList[1].length) { monthIndex = this.dataList[1].length - 1 }
          const dayNum = this.getMonthDay(this.dataList[0][yearIndex].value, this.dataList[1][monthIndex].value)
          const dayStart = (yearIndex === 0 && monthIndex === 0) ? this.startDate.day : 1
          const dayEnd = (yearIndex === this.dataList[0].length - 1 && monthIndex === this.dataList[1].length - 1) ? this.endDate.day : dayNum
          const dayList = this.initNumCol(dayStart, dayEnd)
          this.$set(this.dataList, 2, dayList)
        }
      }
    },
    
    // 设置当前值，传入字符串
    setValues (str) {
      let values = this.getDate(str)
      if (!values) {
        return
      }
      
      let indexes = []
      let year = values.year
      let month = values.month
      let day = values.day
      if (this.colNum >= DATE_TYPES.year) {
        // 根据year获取索引
        if (year < this.startDate.year || typeof year !== 'number') { year = this.startDate.year }
        if (year > this.endDate.year) { year = this.endDate.year }
        indexes.push(year - this.startDate.year)
      }
      if (this.colNum >= DATE_TYPES.month) {
        // 根据month获取索引
        if (month <= 0 || typeof month !== 'number') { month = 1 }
        if (month > 12) { month = 12 }
        if (year === this.startDate.year && month < this.startDate.month) { month = this.startDate.month }
        if (year === this.endDate.year && month > this.endDate.month) { month = this.endDate.month }
        const monthIndex = (year === this.startDate.year) ? (month - this.startDate.month) : (month - 1)
        indexes.push(monthIndex)
      }
      if (this.colNum >= DATE_TYPES.day) {
        // 根据day获取索引
        const dayNum = this.getMonthDay(year, month)
        if (day <= 0 || typeof day !== 'number') { day = 1 }
        if (day > dayNum) { day = dayNum }
        if (year === this.startDate.year && month === this.startDate.month && day < this.startDate.day) {
          day = this.startDate.day
        }
        if (year === this.endDate.year && month === this.endDate.month && day > this.endDate.day) {
          day = this.endDate.day
        }
        const dayIndex = (year === this.startDate.year && month === this.startDate.month) ? (day - this.startDate.day) : (day - 1)
        indexes.push(dayIndex)
      }
      if (this.colNum >= DATE_TYPES.hour) {
        // 根据hour获取索引
        let hour = (typeof values.hour === 'number') ? values.hour : 0
        indexes.push(hour >= 0 ? hour % 24 : 0)
      }
      if (this.colNum >= DATE_TYPES.min) {
        // 根据min获取索引
        let min = (typeof values.min === 'number') ? values.min : 0
        indexes.push(min >= 0 ? min % 60 : 0)
      }
      // 模拟onChange事件，并手动触发
      const event = {
        isSet: true,
        detail: {
          value: indexes
        }
      }
      this.changeHandler(event)
    },
    
    /* @section 一些常规的工具函数 */
    // 给定起始值数字与结束值数字，初始化某列
    initNumCol (start = 0, end = 0) {
      let list = []
      for (let i = start; i <= end; i++) {
        let obj = {
          text: i.toString(),
          value: i
        }
        list.push(obj)
      }
      return list
    },
    
    // 获取某个月的天数
    getMonthDay (year, month) {
      switch(month) {
        case 4:
        case 6:
        case 9:
        case 11:
          return 30
        case 2:
          if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
            return 29
          }
          return 28
        default:
          return 31
      }
    },
    
    // 转换初始化的日期对象
    getDate (str) {
      if (str === 'now') {
        return this.dateTrans(new Date())
      }
      return this.dateTrans(new Date(str))
    },
    
    dateTrans (date) {
      if (!this.isDate(date)) {
        return null
      }
      
      return {
        year: date.getFullYear(),
        month: date.getMonth() + 1,
        day: date.getDate(),
        hour: date.getHours(),
        min: date.getMinutes(),
        second: date.getSeconds()
      }
    },
    
    isDate (obj) {
      // Invalid Date 不合法，将不被识别
      return Object.prototype.toString.call(obj) === '[object Date]' && !isNaN(obj.getTime())
    }
  },
  created () {
    this.set(this.start, this.end, this.values)
  }
}